package com.paomi.client.net;

import android.text.TextUtils;
import android.util.Log;

import com.paomi.client.bean.UserUtils;
import com.paomi.client.utils.MD5Utils;
import com.paomi.client.widget.click.CheckNetwork;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by pc on 2018/10/24
 * Describe:网络请求
 * com.paomi.client.net
 */
public class Api {
    private ApiService service;
    Retrofit retrofit;
    private static String url;

    private static class SingletonHolder {
        private static final Api INSTANCE = new Api(url);
    }

    @CheckNetwork
    public static ApiService getInstanceService(String getUrl) {
        return new Api(getUrl).service;
    }

    private Api(String url) {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);//打印请求数据,上线后删除
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.readTimeout(1, TimeUnit.MINUTES);
        httpClient.addInterceptor(new HeaderInterceptor());
        httpClient.addInterceptor(logging);
        retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(httpClient.build())
                .build();
        service = retrofit.create(ApiService.class);
    }

    private static final Charset UTF8 = Charset.forName("UTF-8");
    private String headerBodyString = "";

    /**
     * 添加头部参数
     * 参数名	是否必选	注释
     * pm_pls	true	0（PC端） 1（苹果APP） 2（安卓APP） 3（H5）
     * pm_sign	true	参数验证，
     * pm_sign生成规则
     * 以登录为例，请求的相关参数拼接成get请求参数。使用MD5来进行数据加密
     * mobile=18727***490&loginType=1&password=aa123456
     * atk	false	已登录用户的token(用户数据接口必传)
     * pm_user	false	该值设置为 true时，将返回已登录用户信息(前提是操作成功 或 操作失败)
     */
    private class HeaderInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            //拼接参数后进行MD5加密
            if (chain.request().body() instanceof FormBody) {//post
                headerBodyString = bodyToString(chain.request().body());
            } else if (chain.request().body() instanceof MultipartBody) {//上传文件
                headerBodyString = mutiBodyToString(chain.request());
                //另一种方法，只对“file=”做了处理
//                MultipartBody multipartBody=(MultipartBody) chain.request().body();
//                headerBodyString = multipartBody.part(0).headers().toString().trim();
//                if(headerBodyString.contains("filename=")){
//                    String[] get=headerBodyString.split("filename=");
//                    String one=get[0].substring(get[0].length()-7,get[0].length()-3);
//                    String two=get[1].substring(1,get[1].length()-1);
////                    String one=get[0].substring(get[0].length()-8,get[0].length()-2);
////                    String two=get[1].substring(1,get[1].length()-1);
//                    headerBodyString=one+"="+two;
//                }
            } else {//get方式
                headerBodyString = getToString(chain.request());
            }
            Log.e("headerBodyString", headerBodyString);
//            formBodyBuilder.add("pm_sign",MD5Utils.MD5(postBodyString));
            String token = getToken();
            Request request = chain.request().newBuilder().addHeader("pm_pls", "2").addHeader("pm_sign", MD5Utils.MD5(headerBodyString)).addHeader("atk", token).addHeader("pm_user", "true").build();
            HttpUrl url = request.url().newBuilder().build();
            if (request.method() == "GET") {
                request = request.newBuilder().url(url).build();
            } else if (request.method() == "POST") {
                if (request.url().toString().contains("upload")) {
                    request = request.newBuilder().url(url).build();
                } else {
                    Request.Builder builder1 = request.newBuilder();
                    request = builder1.url(url).build();
//                    addPostParam(request, request.newBuilder());
                    return chain.proceed(request);
                }
            }
            return chain.proceed(request);
//            if (TextUtils.isEmpty(token)) {
//                //没有登录的情况下
//
//            }
        }

        /**
         * POST请求添加公共参数
         */
        public void addPostParam(Request request, Request.Builder builder) {
            // process post body inject
            if (request.method().equals("POST") && request.body().contentType().subtype().equals("x-www-form-urlencoded")) {
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                formBodyBuilder.add("atk", getToken());
                RequestBody formBody = formBodyBuilder.build();
                String postBodyString = bodyToString(request.body());
                postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
                formBodyBuilder.add("pm_sign", postBodyString);
                builder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString));
            }
        }

        private String getToken() {
            if (UserUtils.getInstance().getUserInfo() != null){
                return UserUtils.getInstance().getUserInfo().getReturnData();
            }
            return "";
        }
    }

    /**
     * 拼接post的参数
     *
     * @param request
     * @return
     */
    private static String bodyToString(final RequestBody request) {
        String extendStr="";
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            if (copy != null)
                copy.writeTo(buffer);
            else
                return "";
            //对参数解码
            try {
                extendStr = URLDecoder.decode(buffer.readUtf8(),"utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return extendStr;
        } catch (final IOException e) {
            return "did not work";
        }
    }

    /**
     * 对上传文件添加统一解析
     *
     * @param request
     * @return
     */
    private String mutiBodyToString(Request request) {
        Map<String, String> signParams = new HashMap<>(); // 假设你的项目需要对参数进行签名
        MultipartBody requestBody = (MultipartBody) request.body();
        MultipartBody.Builder multipartBodybuilder = new MultipartBody.Builder();
        if (requestBody != null) {
            for (int i = 0; i < requestBody.parts().size(); i++) {
                MultipartBody.Part part = requestBody.part(i);
                multipartBodybuilder.addPart(part);

          /*
           上传文件时，请求方法接收的参数类型为RequestBody或MultipartBody.Part参见ApiService文件中uploadFile方法
           RequestBody作为普通参数载体，封装了普通参数的value; MultipartBody.Part即可作为普通参数载体也可作为文件参数载体
           当RequestBody作为参数传入时，框架内部仍然会做相关处理，进一步封装成MultipartBody.Part，因此在拦截器内部，
           拦截的参数都是MultipartBody.Part类型
           */

          /*
           1.若MultipartBody.Part作为文件参数载体传入，则构造MultipartBody.Part实例时，
           需使用MultipartBody.Part.createFormData(String name, @Nullable String filename, RequestBody body)方法，
           其中name参数可作为key使用(因为你可能一次上传多个文件，服务端可以此作为区分)且不能为null，
           body参数封装了包括MimeType在内的文件信息，其实例创建方法为RequestBody.create(final @Nullable MediaType contentType, final File file)
           MediaType获取方式如下：
           String fileType = FileUtil.getMimeType(file.getAbsolutePath());
           MediaType mediaType = MediaType.parse(fileType);

           2.若MultipartBody.Part作为普通参数载体，建议使用MultipartBody.Part.createFormData(String name, String value)方法创建Part实例
            name可作为key使用，name不能为null,通过这种方式创建的实例，其RequestBody属性的MediaType为null；当然也可以使用其他方法创建
           */

          /*
           提取非文件参数时,以RequestBody的MediaType为判断依据.
           此处提取方式简单暴力。默认part实例的RequestBody成员变量的MediaType为null时，part为非文件参数
           前提是:
           a.构造RequestBody实例参数时，将MediaType设置为null
           b.构造MultipartBody.Part实例参数时,推荐使用MultipartBody.Part.createFormData(String name, String value)方法，或使用以下方法
            b1.MultipartBody.Part.create(RequestBody body)
            b2.MultipartBody.Part.create(@Nullable Headers headers, RequestBody body)
            若使用方法b1或b2，则要求

           备注：
           您也可根据需求修改RequestBody的MediaType，但尽量保持外部传入参数的MediaType与拦截器内部添加参数的MediaType一致，方便统一处理
           */

                MediaType mediaType = part.body().contentType();
                if (mediaType != null) {
                    String normalParamKey;
                    String normalParamValue;
                    try {
                        normalParamValue = getParamContent(requestBody.part(i).body());
                        Headers headers = part.headers();
                        if (!TextUtils.isEmpty(normalParamValue) && headers != null) {
                            for (String name : headers.names()) {
                                String headerContent = headers.get(name);
                                if (!TextUtils.isEmpty(headerContent)) {
                                    String[] normalParamKeyContainer = headerContent.split("name=\"");
                                    if (normalParamKeyContainer.length == 2) {
                                        normalParamKey = normalParamKeyContainer[1].split("\"")[0];
                                        signParams.put(normalParamKey, normalParamValue);
                                        break;
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        Log.e("signParams1", signParams.toString());
        String pamera = "";
        for (String paramKey : signParams.keySet()) {
            pamera = paramKey + "=" + signParams.get(paramKey);
        }
        return pamera;
    }

    /**
     * 获取常规post请求参数
     */
    private String getParamContent(RequestBody body) throws IOException {
        Buffer buffer = new Buffer();
        body.writeTo(buffer);
        return buffer.readUtf8();
    }

    /**
     * 获取常规get请求参数
     *
     * @param request
     * @return
     */
    private String getToString(Request request) {
        String pamera = "";
        String url = request.url().toString();
        int separatorIndex = url.lastIndexOf("?");
        if (separatorIndex == -1) {
            pamera = "";
        } else {
            pamera = url.substring(url.lastIndexOf("?") + 1, url.length());
            //对参数解码
            try {
                pamera = URLDecoder.decode(pamera,"utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        return pamera;
    }

}
